﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SmartChess
{
    public class GameRules
    {
        ChessMove move;
        public Boolean IsLegal(ChessMove move, Game game)
        {
            if (move.CurrentColumn == move.TargetColumn && move.CurrentRow == move.TargetRow) // Blockt das "selbst Rausschmeißen"
            {
                return false;
            }
            if (move.PlayerId == 0)
            {
                switch (game.GetUnit(move.CurrentRow, move.CurrentColumn))
                {
                    case Game.UNIT.BBishop:
                        return RuleBBishop(move, game);
                    case Game.UNIT.BKing:
                        return RuleBKing(move, game);
                    case Game.UNIT.BKnight:
                        return RuleBKnight(move, game);
                    case Game.UNIT.BPawn:
                        return RuleBPawn(move, game);
                    case Game.UNIT.BQueen:
                        return RuleBQueen(move, game);
                    case Game.UNIT.BRook:
                        return RuleBRook(move, game);
                    default:
                        return false;
                }
            }
            else if (move.PlayerId == 1)
            {
                switch (game.GetUnit(move.CurrentRow, move.CurrentColumn))
                {
                    case Game.UNIT.WBishop:
                        return RuleWBishop(move, game);
                    case Game.UNIT.WKing:
                        return RuleWKing(move, game);
                    case Game.UNIT.WKnight:
                        return RuleWKnight(move, game);
                    case Game.UNIT.WPawn:
                        return RuleWPawn(move, game);
                    case Game.UNIT.WQueen:
                        return RuleWQueen(move, game);
                    case Game.UNIT.WRook:
                        return RuleWRook(move, game);
                    default:
                        return false;
                }
            }
            return false;

        }

        private bool RuleWPawn(ChessMove move, Game game)
        {
            int CurrentField = (((move.CurrentRow + 2) * 10) + (move.CurrentColumn + 1));
            int TargetField = (((move.TargetRow + 2) * 10) + (move.TargetColumn + 1));
            if (game.GetUnit(move.TargetRow, move.TargetColumn) == Game.UNIT.Free)
            {
                if (CurrentField - 10 == TargetField) // Schritt nach vorne.
                {
                    return true;
                }
                else if ((CurrentField - 20 == TargetField) && (move.CurrentRow == 6)) //Zwei Schitte nach vorn, wenn auf Startfeld
                {
                    if (game.Board[CurrentField - 10] != 0) // Weg darf nicht blockiert sein
                    {
                        return false;
                    }
                    return true;
                }
            }
            if ((CurrentField - 9 == TargetField || CurrentField - 11 == TargetField)) // Seitwärts schlagen
            {
                if (game.BlackAt(move.TargetRow, move.TargetColumn))    //nur wenn feindliche Figur vorhanden
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        private bool RuleWRook(ChessMove move, Game game)
        {
            int CurrentField = (((move.CurrentRow + 2) * 10) + (move.CurrentColumn + 1));
            int TargetField = (((move.TargetRow + 2) * 10) + (move.TargetColumn + 1));
            if (!game.WhiteAt(move.TargetRow, move.TargetColumn))
            {
                if ((CurrentField - TargetField) % 10 == 0) // Bewegung vertikal
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 10; i < Math.Max(TargetField, CurrentField); i += 10) // Weg darf nicht blockiert sein.
                    {
                        if (game.Board[i] != 0)
                        {

                            return false;
                        }
                    }
              
                    return true;
                }
                else if (Math.Abs(CurrentField - TargetField) < 8) // Bewegung horizontal
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 1; i < Math.Max(TargetField, CurrentField); i++) // Weg darf nicht blockiert sein.
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                   
                    return true;
                }
            }
            return false;
        }

        private bool RuleWQueen(ChessMove move, Game game)
        {
            int CurrentField = (((move.CurrentRow + 2) * 10) + (move.CurrentColumn + 1));
            int TargetField = (((move.TargetRow + 2) * 10) + (move.TargetColumn + 1));
            if (!game.WhiteAt(move.TargetRow, move.TargetColumn))
            {
                if ((CurrentField - TargetField) % 10 == 0) // Bewegung vertikal
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 10; i < Math.Max(TargetField, CurrentField); i += 10) // Weg darf nicht blockiert sein.
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else if (Math.Abs(CurrentField - TargetField) < 8) // Bewegung horizontal
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 1; i < Math.Max(TargetField, CurrentField); i++) // Weg darf nicht blockiert sein.
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else if (((Math.Abs(CurrentField - TargetField) % 11) == 0)) // Bewegung schräg rechts-unten und links-oben
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 11; i < Math.Max(TargetField, CurrentField); i += 11) // Weg darf nicht blockiert sein.
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else if ((Math.Abs(CurrentField - TargetField) % 9) == 0) // Bewegung schräg  rechts-oben und links-unten
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 9; i < Math.Max(TargetField, CurrentField); i += 9) // Weg darf nicht blockiert sein.
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else
                    return false;
            }
            return false;
        }

        private bool RuleWKnight(ChessMove move, Game game)
        {
            int currentField = ((move.CurrentRow + 2) * 10) + (move.CurrentColumn + 1);
            int targetField = ((move.TargetRow + 2) * 10) + (move.TargetColumn + 1);
            if (!game.WhiteAt(move.TargetRow, move.TargetColumn))
            {
                // Es werden nur die Möglichen Felder zugelassen
                if (currentField + 8 == targetField)
                    return true;
                else if (currentField + 12 == targetField)
                    return true;
                else if (currentField + 19 == targetField)
                    return true;
                else if (currentField + 21 == targetField)
                    return true;
                else if (currentField - 8 == targetField)
                    return true;
                else if (currentField - 12 == targetField)
                    return true;
                else if (currentField - 19 == targetField)
                    return true;
                else if (currentField - 21 == targetField)
                    return true;
                else
                    return false;
            }
            return false;
        }

        private bool RuleWKing(ChessMove move, Game game)
        {
            int CurrentField = (((move.CurrentRow + 2) * 10) + (move.CurrentColumn + 1));
            int TargetField = (((move.TargetRow + 2) * 10) + (move.TargetColumn + 1));
            if (!game.WhiteAt(move.TargetRow, move.TargetColumn))
            {
                if (Math.Abs(CurrentField - TargetField) == 1) // Ein Schritt vertikal
                {
                    return true;
                }
                else if (Math.Abs(CurrentField - TargetField) == 10) //Ein Schritt horizontal
                {
                    return true;
                }
                else if (Math.Abs(CurrentField - TargetField) == 9) //Ein Schritt schräg  rechts-unten und links-oben
                {
                    return true;
                }
                else if (Math.Abs(CurrentField - TargetField) == 11) //Ein Schritt rechts-oben und links-unten
                {
                    return true;
                }
                else if ((CurrentField == 95 && TargetField == 97) && game.isCastlingRightforWhitePossible() )
                {
                        if ((game.Board[97] == 0 && game.Board[96] == 0))
                            return true;
                }
                else if ((CurrentField == 95 && TargetField == 92)&& game.isCastlingLeftforWhitePossible())
                {
                        if (game.Board[92] == 0 && game.Board[93] == 0 && game.Board[94]==0)
                            return true;
                }

            }
            return false;
        }

        private bool RuleWBishop(ChessMove move, Game game)
        {
            int CurrentField = (((move.CurrentRow + 2) * 10) + (move.CurrentColumn + 1));
            int TargetField = (((move.TargetRow + 2) * 10) + (move.TargetColumn + 1));
            if (!game.WhiteAt(move.TargetRow, move.TargetColumn))
            {
                if (((Math.Abs(CurrentField - TargetField) % 11) == 0)) // Bewegung schräg rechts-unten und links-oben
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 11; i < Math.Max(TargetField, CurrentField); i += 11)// Weg darf nicht blockiert sein.
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else if ((Math.Abs(CurrentField - TargetField) % 9) == 0) // Bewegung schräg  rechts-oben und links-unten
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 9; i < Math.Max(TargetField, CurrentField); i += 9)  // Weg darf nicht blockiert sein.
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else
                    return false;
            }
            return false;
        }

        private bool RuleBRook(ChessMove move, Game game)
        {
            int CurrentField = (((move.CurrentRow + 2) * 10) + (move.CurrentColumn + 1));
            int TargetField = (((move.TargetRow + 2) * 10) + (move.TargetColumn + 1));
            if (!game.BlackAt(move.TargetRow, move.TargetColumn))
            {
                if ((CurrentField - TargetField) % 10 == 0) // Bewegung vertikal
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 10; i < Math.Max(TargetField, CurrentField); i += 10) // Weg darf nicht blockiert sein.
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }                   
                    return true;
                }
                else if (Math.Abs(CurrentField - TargetField) < 8)// Bewegung horizontal
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 1; i < Math.Max(TargetField, CurrentField); i++) // Weg darf nicht blockiert sein.
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                  
                    return true;
                }
            }
            return false;
        }

        private bool RuleBQueen(ChessMove move, Game game)
        {
            int CurrentField = (((move.CurrentRow + 2) * 10) + (move.CurrentColumn + 1));
            int TargetField = (((move.TargetRow + 2) * 10) + (move.TargetColumn + 1));
            if (!game.BlackAt(move.TargetRow, move.TargetColumn))
            {
                if ((CurrentField - TargetField) % 10 == 0)
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 10; i < Math.Max(TargetField, CurrentField); i += 10)
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else if (Math.Abs(CurrentField - TargetField) < 8)
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 1; i < Math.Max(TargetField, CurrentField); i++)
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else if (((Math.Abs(CurrentField - TargetField) % 11) == 0))
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 11; i < Math.Max(TargetField, CurrentField); i += 11)
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else if ((Math.Abs(CurrentField - TargetField) % 9) == 0)
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 9; i < Math.Max(TargetField, CurrentField); i += 9)
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else
                    return false;
            }
            return false;
        }

        private bool RuleBPawn(ChessMove move, Game game)
        {
            int CurrentField = (((move.CurrentRow + 2) * 10) + (move.CurrentColumn + 1));
            int TargetField = (((move.TargetRow + 2) * 10) + (move.TargetColumn + 1));
            if (game.GetUnit(move.TargetRow, move.TargetColumn) == Game.UNIT.Free)
            {
                if (CurrentField + 10 == TargetField)
                {
                    return true;
                }
                else if ((CurrentField + 20 == TargetField) && (move.CurrentRow == 1))
                {
                    if (game.Board[CurrentField + 10] != 0)
                    {
                        return false;
                    }
                    return true;
                }
            }
            if ((CurrentField + 9 == TargetField || CurrentField + 11 == TargetField))
            {
                if (game.WhiteAt(move.TargetRow, move.TargetColumn))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        private bool RuleBKnight(ChessMove move, Game game)
        {
            int[] Board = game.GetBoard();
            int currentField = ((move.CurrentRow + 2) * 10) + (move.CurrentColumn + 1);
            int targetField = ((move.TargetRow + 2) * 10) + (move.TargetColumn + 1);
            if (!game.BlackAt(move.TargetRow, move.TargetColumn))
            {
                if (currentField + 8 == targetField)
                    return true;
                else if (currentField + 12 == targetField)
                    return true;
                else if (currentField + 19 == targetField)
                    return true;
                else if (currentField + 21 == targetField)
                    return true;
                else if (currentField - 8 == targetField)
                    return true;
                else if (currentField - 12 == targetField)
                    return true;
                else if (currentField - 19 == targetField)
                    return true;
                else if (currentField - 21 == targetField)
                    return true;
                else
                    return false;
            }
            return false;
        }

        private bool RuleBKing(ChessMove move, Game game)
        {
            int CurrentField = (((move.CurrentRow + 2) * 10) + (move.CurrentColumn + 1));
            int TargetField = (((move.TargetRow + 2) * 10) + (move.TargetColumn + 1));
            if (!game.BlackAt(move.TargetRow, move.TargetColumn))
            {
                if (Math.Abs(CurrentField - TargetField) == 1)
                {
                    return true;
                }
                else if (Math.Abs(CurrentField - TargetField) == 10)
                {
                    return true;
                }
                else if (Math.Abs(CurrentField - TargetField) == 9)
                {
                    return true;
                }
                else if (Math.Abs(CurrentField - TargetField) == 11)
                {
                    return true;
                }
                else if ((CurrentField == 25 && TargetField == 27) && game.isCastlingRightforBlackPossible() )
                {
                        if ((game.Board[27] == 0 && game.Board[26] == 0) || (game.Board[22] == 0 && game.Board[23] == 0))
                            return true;
                }
                else if ((CurrentField == 25 && TargetField == 22) && game.isCastlingLeftforBlackPossible())
                {
                        if (game.Board[22] == 0 && game.Board[23] == 0 && game.Board[24]==0)
                            return true;
                }
            }
            return false;
        }

        private bool RuleBBishop(ChessMove move, Game game)
        {
            int CurrentField = (((move.CurrentRow + 2) * 10) + (move.CurrentColumn + 1));
            int TargetField = (((move.TargetRow + 2) * 10) + (move.TargetColumn + 1));
            if (!game.BlackAt(move.TargetRow, move.TargetColumn))
            {
                if (((Math.Abs(CurrentField - TargetField) % 11) == 0))
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 11; i < Math.Max(TargetField, CurrentField); i += 11)
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else if ((Math.Abs(CurrentField - TargetField) % 9) == 0)
                {
                    for (int i = Math.Min(TargetField, CurrentField) + 9; i < Math.Max(TargetField, CurrentField); i += 9)
                    {
                        if (game.Board[i] != 0)
                        {
                            return false;
                        }
                    }
                    return true;
                }
                else
                    return false;
            }
            return false;
        }
    }
}
